#!/usr/bin/env python
# -*- coding: utf-8 -*-

#
# This program is free software; you can redistribute it and/or modify  
# it under the terms of the GNU General Public License as published by  
# the Free Software Foundation; either version 2 of the License, or     
# (at your option) any later version.                                   
#                                                                         
# A copy of the license can be found in the license.txt file supplied   
# with this software or at: http://www.gnu.org/copyleft/gpl.html       
#


import struct

from spinage.help.protocol.protocol import Protocol,ProtocolFactory, PC_OK, PC_SIZE_FORMAT_ERROR

from spinage.help import logging


class   SimpleTextSizeProtocol(Protocol) :
    
    def __init__(self) :
        self._logger = logging.getLogger(self.__class__.__name__)

        self._io_stream = None

        self._on_air = False
        self._callback = None
        self._request = None
        ## __init__()

    def bind(self, connection) :
        self._io_stream = connection

        self._on_air = False
        ## bind()

    def sendrecv(self, data, callback=None) :
        '''
        @param data request data to send
        @param callback handle to function callback(status_code, data_or_error, request=None)
        '''
        if self._on_air :
            return False

        self._on_air = True

        self._request = data
        self._callback = callback

        #self._logger.debug('%s::sendrecv() ...', self.__class__.__name__)
        #self._logger.debug('%s::sendrecv() callback:%r', self.__class__.__name__, self._callback)

        size = struct.pack('!I', len(data))
        data_out = ''.join((size, data))
        self._io_stream.write( data_out, self.__onMessageOut )
        #self._io_stream.write( size )
        #self._io_stream.write( data, self.__onMessageOut )
        
        self._io_stream.read_bytes( struct.calcsize('!I'), self.__onMessageSizeGot)
        return True
        ## sendrecv()

    def send(self, data, callback=None) :
        '''
        @param data request data to send
        @param callback handle to function callback(status_code, data_or_error, request=None)
        '''
        if self._on_air :
            return False

        self._on_air = True

        self._request = data
        self._callback = callback

        #self._logger.debug('%s::send() ...', self.__class__.__name__)

        size = struct.pack('!I', len(data))
        data_out = ''.join((size, data))
        self._io_stream.write( data_out, self.__onMessagePut )

        return True
        ## send()

    def recv(self, callback=None) :
        '''
        @param callback handle to function callback(status_code, data_or_error, request=None)
        '''
        if self._on_air :
            return False

        self._on_air = True

        self._request = None
        self._callback = callback
        
        #self._logger.debug('%s::recv() ...', self.__class__.__name__)
        #self._logger.debug('%s::recv() callback:%r', self.__class__.__name__, self._callback)

        self._io_stream.read_bytes( struct.calcsize('!I'), self.__onMessageSizeGot)
        return True
        ## recv()

    ###################################################################

    def __onMessagePut(self) :
        self._on_air = False

        #self._logger.debug('%s::__onMessagePut() message is out', self.__class__.__name__)

        if self._callback :
            callback = self._callback
            self._callback = None

            request = self._request
            self._request = None

            callback( PC_OK, None, request )
        ## __onMessagePut()


    def __onMessageSizeGot(self, size_str) :
        try :
            size_tuple = struct.unpack('!I', size_str)
        except :
            if self._callback :
                callback = self._callback
                self._callback = None

                request = self._request
                self._request = None

                callback( PC_SIZE_FORMAT_ERROR, None, request )

            self._on_air = False
            return False

        if (len(size_tuple) != 1) and (not isinstance(size_tuple[0], int)) :
            if self._callback :
                callback = self._callback
                self._callback = None

                request = self._request
                self._request = None

                callback( PC_SIZE_FORMAT_ERROR, None, request )
            self._on_air = False
            return False

        size = size_tuple[0]

        #self._logger.debug('%s::__onMessageSizeGot() size=%r', self.__class__.__name__, size)

        if size < 1 :
            if self._callback :
                callback = self._callback
                self._callback = None

                request = self._request
                self._request = None

                callback( PC_OK, '', request )

        self._io_stream.read_bytes( size, self.__onMessageGot )
        ## __onMessageSizeGot()


    def __onMessageGot(self, data) :
        self._on_air = False

        #if len(data) < 64 :
        #    self._logger.debug('%s::__onMessageGot() data=%r ...', self.__class__.__name__, data)
        #else :
        #    self._logger.debug('%s::__onMessageGot() data-size=%d ...', self.__class__.__name__, len(data))

        if self._callback :
            callback = self._callback
            self._callback = None

            request = self._request
            self._request = None

            callback( PC_OK, data, request )
        ## __onMessageGot()


    def __onMessageOut(self) :
        # this is just for send-recv round
        #self._logger.debug('%s::__onMessageOut() request is out, and wait for response ...', self.__class__.__name__)
        pass
        ## __onMessageOut()

    ## class SimpleTextSizeProtocol

class   SimpleTextSizeProtocolFactory(ProtocolFactory) :

    def getInstance(self) :
        return SimpleTextSizeProtocol()
        ## getInstance()

    ## class SimpleTextSizeProtocolFactory

